package org.svnadmin.service;

import com.gargoylesoftware.htmlunit.BrowserVersion;
import com.gargoylesoftware.htmlunit.NicelyResynchronizingAjaxController;
import com.gargoylesoftware.htmlunit.WebClient;
import com.gargoylesoftware.htmlunit.html.*;
import org.springframework.stereotype.Service;
import org.svnadmin.util.EncryptUtil;
import org.svnadmin.util.SystemUtil;
import org.tmatesoft.svn.core.SVNDirEntry;
import org.tmatesoft.svn.core.SVNNodeKind;

import java.io.IOException;
import java.util.*;

/**
 * CollaNetSvn浏览器仿真模拟器
 *
 * @author hewenjie
 * @data 2021/6/28
 */
@Service(SimulationService.BEAN_NAME)
public class SimulationService {

    /**
     * Bean名称
     */
    public static final String BEAN_NAME = "simulationService";

    private String url() {
        return SystemUtil.reptile().get("url");
    }

    private WebClient webClient = null;

    public void close() {
        if (!Objects.isNull(webClient)) {
            webClient.close();
        }
    }

    /**
     * 获取仓库列表
     *
     * @return List<String>
     * @throws IOException
     */
    public Collection<SVNDirEntry> listRepository(){
        List<SVNDirEntry> res = new ArrayList<>();
        try {
            HtmlPage homePage = homePage(url());
            List<?> objs = homePage.getByXPath("/html/body/div[1]/div/div/div/ul[1]/li[1]/a");
            if (objs.size() == 0) {
                return res;
            }
            HtmlPage repositoryPage = ((HtmlAnchor) objs.get(0)).click();
            if(!repositoryPage.asXml().contains("datatable_length")){
                return res;
            }
            HtmlSelect htmlSelect = repositoryPage.getElementByName("datatable_length");
            htmlSelect.setSelectedIndex(htmlSelect.getOptionSize() - 1);
            HtmlTable table = repositoryPage.getHtmlElementById("datatable");
            for (int i = 1; i < table.getRowCount(); i++) {
                SVNDirEntry svnDirEntry = new SVNDirEntry(null, null, table.getCellAt(i, 1).asText(), SVNNodeKind.DIR, 0, false, 1024, new Date(), "");
                res.add(svnDirEntry);
            }
            return res;
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            close();
        }
        return res;
    }

    /**
     * 修改svn密码
     *
     * @param account 账号
     * @param pwd     密码
     * @return boolean
     * @throws IOException
     */
    public boolean updatePwd(String account, String pwd){
        HtmlPage editUserPage = getEditUserPage(account);
        if (editUserPage == null) {
            return false;
        }
        return updatePwdHandle(editUserPage, account, pwd);
    }

    /**
     * 添加用户
     *
     * @param account 账号
     * @param name    名称
     * @param pwd     密码
     * @param email   邮箱
     * @return boolean
     * @throws IOException
     */
    public boolean addUser(String account, String name, String pwd, String email) {
        try {
            HtmlPage userPage = userPage(url());
            if (Objects.isNull(userPage)) {
                return false;
            }
            HtmlSubmitInput createUser = (HtmlSubmitInput) userPage.getElementById("listViewAction_create");
            HtmlPage addUserPage = createUser.click();
            HtmlForm addUserForm = (HtmlForm) addUserPage.getByXPath("/html/body/div[4]/div/div[2]/div[2]/form").get(0);
            HtmlTextInput addUserAccountInput = (HtmlTextInput) addUserForm.getElementsByAttribute("input", "name", "username").get(0);
            HtmlTextInput addUserNameInput = (HtmlTextInput) addUserForm.getElementsByAttribute("input", "name", "realUserName").get(0);
            HtmlPasswordInput addUserPwdInput = (HtmlPasswordInput) addUserForm.getElementsByAttribute("input", "name", "passwd").get(0);
            HtmlPasswordInput addUserConfirmPwdInput = (HtmlPasswordInput) addUserForm.getElementsByAttribute("input", "name", "passwordConfirm").get(0);
            HtmlTextInput addUserEmailInput = (HtmlTextInput) addUserForm.getElementsByAttribute("input", "name", "email").get(0);
            addUserAccountInput.setValueAttribute(account);
            addUserNameInput.setValueAttribute(name);
            addUserPwdInput.setValueAttribute(pwd);
            addUserConfirmPwdInput.setValueAttribute(pwd);
            addUserEmailInput.setValueAttribute(email);

            HtmlSubmitInput addUserSubmit = (HtmlSubmitInput) addUserForm.getElementsByAttribute("input", "type", "submit").get(0);
            HtmlPage resultPage = addUserSubmit.click();
            return resultPage.asXml().contains("User \"" + account + "\" created");
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            close();
        }
        return false;
    }

    /**
     * 删除用户
     *
     * @param account 账号
     * @return boolean
     * @throws IOException
     */
    public boolean deleteUser(String account) {
        HtmlPage editUserPage = getEditUserPage(account);
        if (editUserPage == null) {
            return false;
        }
        return delUser(editUserPage, account);
    }

    private HtmlPage getEditUserPage(String account) {
        try {
            HtmlPage userPage = userPage(url());
            if (Objects.isNull(userPage)) {
                return null;
            }
            HtmlTable table = userPage.getHtmlElementById("datatable");
            HtmlPage editUserPage = findUser(account, table);
            while (editUserPage == null) {
                List<?> nextULList = userPage.getByXPath("/html/body/div[4]/div/div[2]/div[2]/div/div[2]/div[2]/div/ul");//下一页的UL元素
                if (nextULList.size() == 0) {
                    return null;
                }
                HtmlUnorderedList nextUL = (HtmlUnorderedList) nextULList.get(0);
                HtmlListItem nextItem = (HtmlListItem) nextUL.getLastChild();
                String aClass = nextItem.getAttribute("class");
                if (aClass.contains("disabled")) {
                    return null;
                }
                HtmlAnchor anchor = (HtmlAnchor) nextItem.getFirstChild();
                userPage = anchor.click();
                table = userPage.getHtmlElementById("datatable");
                editUserPage = findUser(account, table);
            }
            return editUserPage;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 查找用户
     *
     * @param account 账号
     * @param table   表格
     * @return HtmlPage
     * @throws IOException
     */
    private HtmlPage findUser(String account, HtmlTable table) throws IOException {
        for (int i = 1; i < table.getRowCount(); i++) {
            if (table.getCellAt(i, 0).asText().equals(account)) {
                HtmlAnchor anchor = (HtmlAnchor) table.getCellAt(i, 0).getFirstChild();
                return anchor.click();
            }
        }
        return null;
    }

    private boolean updatePwdHandle(HtmlPage editUserPage, String account, String pwd){
        try {
            HtmlAnchor updatePwdAnchor = (HtmlAnchor) editUserPage.getByXPath("/html/body/div[4]/div/div[2]/div[2]/form/div[1]/div/span/a").get(0);
            HtmlPage updatePwdPage = updatePwdAnchor.click();
            HtmlForm form = (HtmlForm) updatePwdPage.getByXPath("/html/body/div[4]/div/div[2]/div[2]/form").get(0);
            HtmlPasswordInput pwdInput = (HtmlPasswordInput) form.getElementsByAttribute("input", "name", "passwd").get(0);
            HtmlPasswordInput confirmPwdInput = (HtmlPasswordInput) form.getElementsByAttribute("input", "name", "confirmPasswd").get(0);
            pwdInput.setValueAttribute(pwd);
            confirmPwdInput.setValueAttribute(pwd);
            HtmlSubmitInput updateSubmit = (HtmlSubmitInput) form.getElementsByAttribute("input", "name", "_action_update").get(0);
            updateSubmit.removeAttribute("disabled");
            HtmlPage resultPage = updateSubmit.click();
            return resultPage.asXml().contains("User \"" + account + "\" updated");
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            close();
        }
        return false;
    }

    private boolean delUser(HtmlPage editUserPage, String account){
        try{
            HtmlSubmitInput submitInput = (HtmlSubmitInput) editUserPage.getByXPath("/html/body/div[4]/div/div[2]/div[2]/form/div[8]/input[2]").get(0);
            HtmlPage confirmPage = submitInput.click();
            HtmlAnchor confirm = (HtmlAnchor) confirmPage.getByXPath("/html/body/div[4]/div/div[2]/div[2]/form/div[9]/div[3]/a[1]").get(0);
            HtmlPage resultPage = confirm.click();
            return resultPage.asXml().contains("User \"" + account + "\" deleted");
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            close();
        }
       return false;
    }

    private WebClient webClient() {
        WebClient webClient = new WebClient(BrowserVersion.CHROME);
        webClient.getOptions().setThrowExceptionOnScriptError(false);//当JS执行出错的时候是否抛出异常, 这里选择不需要
        webClient.getOptions().setThrowExceptionOnFailingStatusCode(false);//当HTTP的状态非200时是否抛出异常, 这里选择不需要
        webClient.getOptions().setActiveXNative(false);
        webClient.getOptions().setCssEnabled(false);//是否启用CSS, 因为不需要展现页面, 所以不需要启用
        webClient.getOptions().setJavaScriptEnabled(true); //很重要，启用JS
        webClient.setAjaxController(new NicelyResynchronizingAjaxController());//很重要，设置支持AJAX
        return webClient;
    }

    private HtmlPage homePage(String url) throws IOException {
        webClient = webClient();
        HtmlPage loginPage = webClient.getPage(url);

        HtmlForm form = (HtmlForm) loginPage.getElementById("loginForm");
        HtmlTextInput username = (HtmlTextInput) form.getElementsByAttribute("input", "name", "j_username").get(0);
        HtmlPasswordInput password = (HtmlPasswordInput) form.getElementsByAttribute("input", "name", "j_password").get(0);
        username.setValueAttribute(SystemUtil.reptile().get("user"));
        password.setValueAttribute(EncryptUtil.decrypt(SystemUtil.reptile().get("ticket")));
        HtmlSubmitInput submit = (HtmlSubmitInput) form.getElementsByAttribute("input", "type", "submit").get(0);
        return submit.click();
    }

    private HtmlPage userPage(String url) throws IOException {
        HtmlPage homePage = homePage(url);
        List<?> objects = homePage.getByXPath("/html/body/div[1]/div/div/div/ul[1]/li[2]/a");
        if (objects.size() == 0) {
            return null;
        }
        HtmlAnchor anchor = (HtmlAnchor) objects.get(0);

        HtmlPage userPage = anchor.click();
        HtmlSelect htmlSelect = userPage.getElementByName("datatable_length");
        htmlSelect.setSelectedIndex(htmlSelect.getOptionSize() - 1);
        return userPage;
    }

}
